package com.dragon.connector.imServer.session.service;


import com.dragon.connector.imServer.session.LocalSession;
import com.dragon.connector.imServer.session.ServerSession;
import com.dragon.connector.imServer.session.dao.SessionCacheDAO;
import com.dragon.connector.imServer.session.entity.SessionCache;
import com.dragon.connector.imServer.session.entity.UserCache;
import com.dragon.connector.imServer.session.dao.UserCacheDAO;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Data
@Repository("SessionManger")
public class SessionManger {

    @Autowired
    private UserCacheDAO userCacheDAO;

    @Autowired
    private SessionCacheDAO sessionCacheDAO;

    private static SessionManger singleInstance = null;

    // 单聊集合
    private ConcurrentHashMap<String, ServerSession> sessionMap = new ConcurrentHashMap<>();

    // 群聊集合
    private ConcurrentHashMap<String, ChannelGroup> groupMap = new ConcurrentHashMap<>();

    public static SessionManger inst() {
        return singleInstance;
    }

    public static void setSingleInstance(SessionManger singleInstance) {
        SessionManger.singleInstance = singleInstance;
    }

    /**
     * 加入群聊通道
     *
     * @param groupIds
     * @param ctx
     */
    public void addGroupSession(List<String> groupIds, ChannelHandlerContext ctx) {
        for (String groupId : groupIds) {
            // 群不存在,则创建群
            if (groupMap.get(groupId) == null) {
                // 创建不同的channelGroup
                ChannelGroup channels = new DefaultChannelGroup(ctx.executor());
                channels.add(ctx.channel());
                groupMap.put(groupId, channels);
            } else {
                groupMap.get(groupId).add(ctx.channel());
            }
        }
    }

    /**
     * 登录成功之后，增加session对象
     *
     * @param session
     */
    public void addLocalSession(LocalSession session) {
        // 保存本地的session到会话清单
        String sessionId = session.getSessionId();
        sessionMap.put(sessionId, session);
        String uid = session.getUser().getUserId();
        // 缓存session到redis
        SessionCache sessionCache = new SessionCache(uid, sessionId, session.getUser().getPlatform());
        sessionCacheDAO.save(sessionCache);
        // 增加用户的sssion信息到用户缓存
        userCacheDAO.addSession(uid, sessionCache);
    }

    /**
     * 加入群聊
     * @param session
     */
    public void addGroupSession(LocalSession session){
        // 加入群聊
        List<String> groupIds = session.getUser().getGroupIds();
        if (groupIds != null) {
            for (String groupId : groupIds) {
                if (groupMap.get(groupId) == null) {
                    ChannelGroup channels = new DefaultChannelGroup(session.getChannelHandlerContext().executor());
                    channels.add(session.getChannel());
                    groupMap.put(groupId,channels);
                }else{
                    groupMap.get(groupId).add(session.getChannel());
                }
            }
        }
    }

    /**
     * 获取用户的所有session连接
     *
     * @param userId
     * @return
     */
    public List<ServerSession> getSessionsBy(String userId) {
        UserCache userCache = userCacheDAO.get(userId);
        if (userCache == null) {
            log.info("用户：{} 下线了? 没有在缓存中找到记录 ", userId);
            return null;
        }
        Map<String, SessionCache> allSession = userCache.getMap();
        if (allSession == null || allSession.size() == 0) {
            log.info("用户：{} 下线了? 没有任何会话", userId);
            return null;
        }
        List<ServerSession> sessions = new LinkedList<>();
        allSession.values().stream().forEach(sessionCache -> {
            String sid = sessionCache.getSessionId();
            ServerSession session = sessionMap.get(sid);
            if (session == null) {
                sessionMap.put(sid, session);
            }
            sessions.add(session);
        });
        return sessions;
    }

    /**
     * 关闭连接
     *
     * @param ctx 通道
     */
    public void closeSession(ChannelHandlerContext ctx) {
        LocalSession session = ctx.channel().attr(LocalSession.SESSION_KEY).get();

        if (session == null || !session.isValid()) {
            log.error("session is null or isValid");
        }

        session.close();

        this.removeSession(session.getSessionId(), session.getUserId());

        // 通知客服

    }

    public void removeSession(String sessionId, String uid) {
//        if (!sessionMap.containsKey(sessionId)){
//            // 如果之前服务重启之后，sessionMap里面是不会报错东西的，所以和redis数据是不匹配的直接删除
//            // 删除缓存session
//            sessionCacheDAO.remove(sessionId);
//
//            // 分布式：分布式保存user和所有session，根据sessionId 删除用户的会话
//            userCacheDAO.removeSession(uid,sessionId);
//            // 删除本地会话
//            sessionMap.remove(sessionId);
//            return;
//        }
        // 分布式：分布式保存user和所有session，根据sessionId 删除用户的会话
        userCacheDAO.removeSession(uid, sessionId);

        // 删除缓存session
        sessionCacheDAO.remove(sessionId);

        // 删除本地会话
        sessionMap.remove(sessionId);
    }
}
